//////////////////////////////////////////////////////////////////////////////////
// File: alu.v
// Module: alu
// Authors: Cody Cziesler, Nick Desaulniers
// Created: 3/31/11
// Verilog HDL
// Description: Non-pipelined 16-bit ALU
//
// Revision 0.01 - File Created
// Revision 1.00 - Complete, untested
// Revision 2.00 - Removed v, c; fixed z; fixed displays; tested w/ ModelSim (CRC)
// Revision 3.00 - Formatting, Fixed NAND, NOR instructions (CRC)
// Revision 4.00 - Changed up opcodes to represent finalized control logic.
// Revision 5.00 - Reinserted ZERO (CRC)
// Revision 6.00 - Changes always@(...) to always@(*) to make combinational, removed clk_n signal, cleaned up z flag (CRC)
// Revision 7.00 - Fixed tab spacing (CRC)
// Revision 8.00 - Removed latch (CRC)
// Revision 9.00 - Removed rst_n (CRC)
// Revusion 10.00 - Changed params to defines and put into include.v (CRC)
//
// TODO:
//  - Add more flags, put into array
//////////////////////////////////////////////////////////////////////////////////

`include "include.v"

module alu(
  input wire [15:0] a,      // First operand
  input wire [15:0] b,      // Second operand
  input wire [4:0]  opcode, // Opcode for ALU
  output reg [15:0] out,    // Result
  output wire       z       // Zero Flag
);

// Upper bits of multiply
reg [15:0] mult_high_out;

// Z is the zero flag
assign z = (out[15:0] == 16'b0) ? 1'b1 : 1'b0;

always@(*) begin
  mult_high_out = 16'b0;
  out = 16'b0;          // To eliminate latch
  case(opcode)
    `ZERO : begin
      out = 16'b0;
    end
    `CPY : begin
      out = a;
    end
    `ADD : begin
      out = a + b;
    end
    `SUB : begin
      out = a - b;
    end
    `MUL : begin
      {mult_high_out,out} = a * b;
    end
    `AND : begin
      out = a & b;
    end
    `OR : begin
      out = a | b;
    end
    `NOT : begin
      out = ~a;
    end
    `XOR : begin
      out = a ^ b;
    end
    `XNOR : begin
      out = a ^~ b;
    end
    `NAND : begin
      out = ~(a & b);
    end
    `NOR : begin
      out = ~(a | b);
    end
    `LS : begin
      out = a << b;
    end
    `RS : begin
      out = a >> b;
    end
    `NOOP : begin
    end
    `INC : begin
      out = a + 1'b1;
    end
    `DEC : begin
      out = a - 1'b1;
    end
    `LSA : begin
      out = a <<< b;
    end
    `RSA : begin
      out = a >>> b;
    end
    default : begin
    end
  endcase
end

endmodule

